
#include "graphics/pass.h"
#include "graphics/graphicsmanager.h"
#include "graphics/texturemanager.h"

namespace dw
{
namespace graphics
{

																	Pass::Pass()
{
}

void Pass::removeTextureUnitState(const unsigned i)
{
	_textureUnitStates.erase(i);
}

void Pass::setTextureUnitState(const unsigned i, const Renderer::TextureUnit::State& textureUnitState)
{
	_textureUnitStates.insert(std::make_pair(i, textureUnitState));
}

void Pass::setTextureName(const unsigned i, const std::string& textureName)
{
	_textureNames.insert(std::make_pair(i, textureName));
}

void Pass::begin()
{
	TextureUnitStateConstIterator texUnitIter = _textureUnitStates.begin();
	Renderer& renderer(GraphicsManager::getInstance().getRenderer());

	if (_textureUnitStates.size() == 1)
	{
		renderer.setTexture(0, TextureManager::getInstance().getTexture(_textureNames[0]));
		renderer.setTextureUnitState(0, Renderer::TS_TEXCOORD_INDEX, 0);
		renderer.setTextureUnitState(0, Renderer::TS_COLOR_OP,   Renderer::TextureOp::MODULATE);
		renderer.setTextureUnitState(0, Renderer::TS_COLOR_ARG0, Renderer::TextureArg::PREVIOUS);
		renderer.setTextureUnitState(0, Renderer::TS_COLOR_ARG1, Renderer::TextureArg::TEXTURE);
	}
	else if (_textureUnitStates.size() > 1)
	{	
		renderer.setTexture(0, TextureManager::getInstance().getTexture(_textureNames[0]));
		renderer.setTextureUnitState(0, Renderer::TS_TEXCOORD_INDEX, 2);
		renderer.setTextureUnitState(0, Renderer::TS_COLOR_OP,   Renderer::TextureOp::MODULATE);
		renderer.setTextureUnitState(0, Renderer::TS_COLOR_ARG0, Renderer::TextureArg::PREVIOUS);
		renderer.setTextureUnitState(0, Renderer::TS_COLOR_ARG1, Renderer::TextureArg::TEXTURE);

		renderer.setTexture(1, TextureManager::getInstance().getTexture(_textureNames[1]));
		renderer.setTextureUnitState(1, Renderer::TS_TEXCOORD_INDEX, 0);
		renderer.setTextureUnitState(1, Renderer::TS_COLOR_OP,   Renderer::TextureOp::MODULATE);
		renderer.setTextureUnitState(1, Renderer::TS_COLOR_ARG0, Renderer::TextureArg::PREVIOUS);
		renderer.setTextureUnitState(1, Renderer::TS_COLOR_ARG1, Renderer::TextureArg::TEXTURE);
	}

	//for (; texUnitIter != _textureUnitStates.end(); ++texUnitIter)
	//{
	//	Renderer::TextureUnit::State texUnitState;
	//	TextureNameConstIterator texNameIter = _textureNames.find(texUnitIter->first);
	//	ITexture* texture;

	//	if (texNameIter != _textureNames.end())
	//	{
	//		texture = TextureManager::getInstance().getTexture(texNameIter->second);
	//		renderer->setTexture(texUnitIter->first, texture);
	//		uint32 texCoordIndex = texUnitIter->second.value(Renderer::TS_TEXCOORD_INDEX);
	//		renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_TEXCOORD_INDEX, texUnitIter->second.value(Renderer::TS_TEXCOORD_INDEX));
	//		renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_COLOR_OP,   Renderer::TextureOp::MODULATE);
	//		renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_COLOR_ARG0, Renderer::TextureArg::PREVIOUS);
	//		renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_COLOR_ARG1, Renderer::TextureArg::TEXTURE);
	//		//renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_COLOR_OP,   texUnitIter->second.value(Renderer::TS_COLOR_OP));
	//		//renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_COLOR_ARG0, texUnitIter->second.value(Renderer::TS_COLOR_ARG0));
	//		//renderer->setTextureUnitState(texUnitIter->first, Renderer::TS_COLOR_ARG1, texUnitIter->second.value(Renderer::TS_COLOR_ARG1));
	//	}
	//}
}

void Pass::end()
{
	TextureUnitStateConstIterator texUnitIter = _textureUnitStates.begin();
	Renderer& renderer(GraphicsManager::getInstance().getRenderer());

	for (; texUnitIter != _textureUnitStates.end(); ++texUnitIter)
		renderer.setTexture(texUnitIter->first, 0);
}

std::string Pass::getSignature()	const
{
	return "dw::graphics::Pass";
}

void Pass::serialize(ISerializer* serializer) const
{
	//serializer->serialize(_textureUnitStates);
	//serializer->serialize(_textureNames);
}

void Pass::deserialize(ISerializer* serializer)
{
	//serializer->deserialize(_textureUnitStates);
	//serializer->deserialize(_textureNames);
}

std::ostream& operator<<(std::ostream& os, const Pass& pass)
{ 
	uint32 numTextureUnitStates	= static_cast< uint32 >(pass._textureUnitStates.size());
	uint32 numTextureNames				= static_cast< uint32 >(pass._textureNames.size());

	os.write(reinterpret_cast< const char* >(&numTextureUnitStates), sizeof (numTextureUnitStates));
	for (Pass::TextureUnitStateConstIterator iter = pass._textureUnitStates.begin(); iter != pass._textureUnitStates.end(); ++iter)
	{
		os.write(reinterpret_cast< const char* >(&iter->first), sizeof (Pass::TextureUnitStateMap::key_type));
		os << iter->second;
	}
	os.write(reinterpret_cast< const char* >(&numTextureNames), sizeof (numTextureNames));
	for (Pass::TextureNameConstIterator iter = pass._textureNames.begin(); iter != pass._textureNames.end(); ++iter)
	{
		uint32 textureNameLength = static_cast< uint32 >(iter->second.size());

		os.write(reinterpret_cast< const char* >(&iter->first), sizeof (Pass::TextureNameMap::key_type));
		os.write(reinterpret_cast< const char* >(&textureNameLength), sizeof (textureNameLength));
		os.write(iter->second.c_str(), textureNameLength + 1);
	}
	return os;
}

std::istream& operator>>(std::istream& is, Pass& pass)
{
	uint32 numTextureUnitStates;
	uint32 numTextureNames;

	pass._textureUnitStates.clear();
	pass._textureNames.clear();

	is.read(reinterpret_cast< char* >(&numTextureUnitStates), sizeof (numTextureUnitStates));
	for (uint32 i = 0; i < numTextureUnitStates; ++i)
	{
		std::pair<Pass::TextureUnitStateMap::key_type, Pass::TextureUnitStateMap::mapped_type> textureUnitStatePair;
		is.read(reinterpret_cast< char* >(&textureUnitStatePair.first), sizeof (Pass::TextureUnitStateMap::key_type));
		is >> textureUnitStatePair.second;
		pass._textureUnitStates.insert(textureUnitStatePair);
	}
	is.read(reinterpret_cast< char* >(&numTextureNames), sizeof (numTextureNames));
	for (unsigned i = 0; i < numTextureNames; ++i)
	{
		uint32 textureNameLength;
		char* textureName;

		std::pair<Pass::TextureNameMap::key_type, Pass::TextureNameMap::mapped_type> textureNamePair;
		is.read(reinterpret_cast< char* >(&textureNamePair.first), sizeof (Pass::TextureNameMap::key_type));
		is.read(reinterpret_cast< char* >(&textureNameLength), sizeof (textureNameLength));
		textureName = new char[textureNameLength + 1];
		is.read(textureName, textureNameLength + 1);
		textureNamePair.second.assign(textureName, textureNameLength);
		pass._textureNames.insert(textureNamePair);
		TextureManager::getInstance().loadTexture(textureName);
		delete [] textureName;
	}
	return is;
}

} // namespace graphics
} // namespace dw;